package club.ruanx.movie.util;

import club.ruanx.movie.adapter.interceptor.DoubanFileInterceptor;
import club.ruanx.movie.feign.FileServiceClient;
import club.ruanx.spider.common.GlobalThreadPool;
import club.ruanx.util.CollectionUtils;
import club.ruanx.util.FileUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 阮胜
 * @date 2019/2/10 17:28
 */
@Component
@Slf4j
public class FileUploaderWithFeign {
    private final GlobalThreadPool pool;
    private final FileServiceClient fileServiceClient;

    public FileUploaderWithFeign(GlobalThreadPool pool, FileServiceClient fileServiceClient) {
        this.pool = pool;
        this.fileServiceClient = fileServiceClient;
    }

    public String uploadImageFromUrl(List<String> urlList) {
        return this.uploadImageFromUrl(urlList, file -> true);
    }

    public String uploadImageFromUrl(String url) {
        String fileName = url.substring(url.lastIndexOf("/") + 1);
        String systemPath = Objects.requireNonNull(Objects.requireNonNull(ClassUtils.getDefaultClassLoader()).getResource("")).getPath();
        String filePath = downloadImage(url, systemPath, fileName);
        return fileServiceClient.upload(FileUtils.toMultipartFile(new File(filePath)));
    }

    /**
     * 通过图片URL上传到FAST DFS 服务器
     *
     * @param urlList 图片URL列表
     * @return FAST DFS 服务器中的图片URL
     */
    public String uploadImageFromUrl(List<String> urlList, DoubanFileInterceptor doubanFileInterceptor) {
        if (CollectionUtils.isEmpty(urlList)) {
            return "";
        }
        try {
            CountDownLatch latch = new CountDownLatch(urlList.size());
            String systemPath = Objects.requireNonNull(Objects.requireNonNull(ClassUtils.getDefaultClassLoader()).getResource("")).getPath();
            Vector<String> photoVector = new Vector<>(urlList.size());
            urlList.forEach(url -> pool.execute(() -> {
                String fileName = url.substring(url.lastIndexOf("/") + 1);
                String filePath = downloadImage(url, systemPath, fileName);
                photoVector.add(filePath);
                latch.countDown();
            }));
            latch.await(3, TimeUnit.MINUTES);
            List<String> photosUrl = photoVector.stream()
                    .map(File::new)
                    .filter(doubanFileInterceptor::intercept)
                    .map(file -> fileServiceClient.upload(FileUtils.toMultipartFile(file)))
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            return JSON.toJSONString(photosUrl);
        } catch (Exception e) {
            log.error(e.getMessage());
            return "";
        }
    }

    private String downloadImage(String imgUrl, String filePath, String fileName) {
        try {
            URL url = new URL(imgUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            // 设置连接超时时间
            conn.setConnectTimeout(3000);
            InputStream inputStream = null;

            // 正常响应时获取输入流, 在这里也就是图片对应的字节流
            if (conn.getResponseCode() == 200) {
                inputStream = conn.getInputStream();
            }

            byte[] buffer = new byte[1024];
            int length;
            // 这里是输出到工程根目录下
            FileOutputStream fileOutputStream = new FileOutputStream(filePath + fileName);
            // 将输入流循环写到关联文件的输出流
            assert inputStream != null;
            while ((length = inputStream.read(buffer)) > 0) {
                fileOutputStream.write(buffer, 0, length);
            }
            // 释放资源
            inputStream.close();
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return filePath + fileName;
    }
}
